﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.IO;
using Go;

namespace fhs
{
    public class LogMgr
    {
        static LogMgr this_ = new LogMgr();

        public enum Type
        {
            File,
            Info,
            Error,
            Debug,
            Warning,
            Exception
        }

        public struct LogPack
        {
            public DateTime time;
            public Type type;
            public string msg;
        }

        FileStream _logFile;
        shared_strand _strand;
        generator _logAction;
        chan<LogPack> _msgQueue;

        LogMgr()
        {
            _logFile = new FileStream(@".\fhs.log", FileMode.Append);
            _strand = new shared_strand();
            _msgQueue = chan<LogPack>.make(_strand, -1);
            _logAction = generator.tgo(_strand, LogAction);
        }

        static public void File(string msg)
        {
            LogPack log = new LogPack { time = DateTime.Now, type = Type.File, msg = msg };
            this_._msgQueue.post(log);
        }

        static public void Info(string msg)
        {
            LogPack log = new LogPack { time = DateTime.Now, type = Type.Info, msg = msg };
            LogViewForm.obj.Append(log);
            this_._msgQueue.post(log);
        }

        static public void Error(string msg)
        {
            LogPack log = new LogPack { time = DateTime.Now, type = Type.Error, msg = msg };
            LogViewForm.obj.Append(log);
            this_._msgQueue.post(log);
        }

        static public void Debug(string msg)
        {
            LogPack log = new LogPack { time = DateTime.Now, type = Type.Debug, msg = msg };
            LogViewForm.obj.Append(log);
            this_._msgQueue.post(log);
        }

        static public void Warning(string msg)
        {
            LogPack log = new LogPack { time = DateTime.Now, type = Type.Warning, msg = msg };
            LogViewForm.obj.Append(log);
            this_._msgQueue.post(log);
        }

        static public void Excep(string msg)
        {
            LogPack log = new LogPack { time = DateTime.Now, type = Type.Exception, msg = msg };
            LogViewForm.obj.Append(log);
            this_._msgQueue.post(log);
        }

        static public void Close()
        {
            this_._logAction.sync_stop();
        }

        private void ApppendLog(LogPack log)
        {
            try
            {
                byte[] data = Encoding.Default.GetBytes($"{log.time.ToString("yyyy-MM-dd HH:mm:ss.fff")} {log.type}:{log.msg}\r\n");
                _logFile.Write(data, 0, data.Length);
            }
            catch (Exception) { }
        }

        private async Task LogAction()
        {
            generator autoFlush = generator.tgo(_strand, async delegate ()
            {
                while (true)
                {
                    await generator.sleep(3000);
                    try
                    {
                        _logFile.Flush();
                    }
                    catch (Exception) { }
                }
            });
            chan_lost_msg<LogPack> lostMsg = new chan_lost_msg<LogPack>();
            try
            {
                while (true)
                {
                    ApppendLog(await _msgQueue.receive(lostMsg));
                }
            }
            catch (generator.stop_exception)
            {
                await generator.stop_other(autoFlush);
                if (lostMsg.has)
                {
                    ApppendLog(lostMsg.msg);
                }
                try
                {
                    while (true)
                    {
                        ApppendLog(await _msgQueue.try_receive());
                    }
                }
                catch (chan_exception) { }
                _logFile.Dispose();
            }
        }
    }
}
